﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "CmdCreateLinearInstance.h"
#include "IDocument.h"
#include "IFamily.h"
#include "IPointArrayInstanceInput.h"
#include "IModelView.h"
#include "IElementBasicInformation.h"
#include "IGraphicsNodeGroup.h"
#include "IElementModelShape.h"
#include "IGraphicsElementShape.h"
#include "IInstance.h"
#include "IRegenerator.h"
#include "IUiView.h"
#include "IUserTransaction.h"
#include "CommandParameters.h"
#include "UiDocumentViewUtils.h"
#include "IGraphicsMaterialManager.h"
#include "GraphicsNodeUtils.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "ICommandManager.h"
#include "GcmpCommandState.h"
// GBMP
#include "GbmpUiPlatformCommandIds.h"
#include "GbmpGraphicsNodeUtils.h"
#include "UIWorkLevelUtilTemp.h"

#include "ActionDrawStraightElementInput.h"
#include "ActionDrawStraightElementCreator.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;

EXPOSE_DEBUG_MODE(DisablePreviewOnInstanceCreation)

CmdCreateLinearInstance::CmdCreateLinearInstance():
    CommandBase(ID_CMD_CREATE_LINEAR_INSTANCE)
    , m_isPreview(true)
    , m_familyId(ElementId::InvalidID)
    , m_familyTypeName(L"")
{
}

bool CmdCreateLinearInstance::IsEnabled() const
{
    return gcmp::GcmpCommandState::IsInProjectEnvironment() && !gcmp::GcmpCommandState::IsInAnimationEnvironment();
}

bool CmdCreateLinearInstance::IsVisible() const
{
    return gcmp::GcmpCommandState::IsInProjectEnvironment() && !gcmp::GcmpCommandState::IsInAnimationEnvironment();
}

gcmp::OwnerPtr<IAction> CmdCreateLinearInstance::ExecuteCommand(const gcmp::CommandParameters& cmdParams)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(cmdParams.size() == 2, L"创建线式族命令的参数个数应为2",L"GDMPLab",L"2024-03-30");

    auto itor = cmdParams.find(L"FamilyName");
    DBG_WARN_AND_RETURN_UNLESS(itor != cmdParams.end(), nullptr, L"所需的参数不存在",L"GDMPLab",L"2024-03-30");
    std::wstring familyName = itor->second.AsWString();

    itor = cmdParams.find(L"InstanceType");
    DBG_WARN_AND_RETURN_UNLESS(itor != cmdParams.end(), nullptr, L"所需的参数不存在",L"GDMPLab",L"2024-03-30");
    m_familyTypeName = itor->second.AsWString();

    IFamily *pFamily = IFamily::GetFamilyByName(UiDocumentViewUtils::GetCurrentDocument(), familyName);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pFamily, L"根据名字无法找到族",L"GDMPLab",L"2024-03-30");
    m_familyId = pFamily->GetBasicInformation()->GetElementId();
    m_isPreview = true;

    if (DEBUG_MODE(DisablePreviewOnInstanceCreation))
    {
        m_isPreview = false;
    }

    ActionDrawStraightElementInput actionInput;
    actionInput.CommandId = GetCommandId();
    actionInput.DrawLineMode = DrawLineMode::Chained;
    actionInput.LineFinishedCallback = ActionDrawStraightElementInput::CreateOnLineFinishedCallback(&CmdCreateLinearInstance::OnLineFinished, this);
    actionInput.LineUpdateCallback = ActionDrawStraightElementInput::CreateOnLineUpdateCallback(&CmdCreateLinearInstance::OnLineUpdate, this);
    actionInput.PromptMessageCallback = ActionDrawStraightElementInput::CreateDefinePomptMessageCallback(&CmdCreateLinearInstance::DefinePromptMessage, this);

    OwnerPtr<IAction> opAction = ActionDrawStraightElementCreator::Create(actionInput);

    return TransferOwnership(opAction);
}

ElementId CmdCreateLinearInstance::OnLineFinished(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& startPt, const gcmp::Vector3d& endPt,
    const gcmp::ISnap* pStartSnap, const gcmp::ISnap* pEndSnap)
{
    DBG_WARN_AND_RETURN_UNLESS(pCurrentView != nullptr, ElementId::InvalidID, L"当前视图为空",L"GDMPLab",L"2024-03-30");

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_UNLESS(pDoc, ElementId::InvalidID, L"doc为空",L"GDMPLab",L"2024-03-30");

    IModelView* view = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_UNLESS(view, ElementId::InvalidID, L"view为空",L"GDMPLab",L"2024-03-30");

    std::vector<Vector3d> pts;
    pts.emplace_back(Vector3d(startPt.X(), startPt.Y(), startPt.Z()));
    pts.emplace_back(Vector3d(endPt.X(), endPt.Y(), endPt.Z()));

    gcmp::OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, (GBMP_TR(L"创建GBMP普通线式族实例")));
    DBG_WARN_AND_RETURN_UNLESS(ut, ElementId::InvalidID, L"ut为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IPointArrayInstanceInput> opPointArrayInstanceInput = IPointArrayInstanceInput::Create(UiDocumentViewUtils::GetCurrentDocument(), UIWorkLevelUtilTemp::GetWorkLevelId(view), m_familyId, m_familyTypeName, pts);
    IInstance* instance = IInstance::CreateByPointArray(opPointArrayInstanceInput.get());
    DBG_WARN_AND_RETURN_UNLESS(instance, ElementId::InvalidID, L"instance为空",L"GDMPLab",L"2024-03-30");

    ElementId res = instance->GetBasicInformation()->GetElementId();
    DBG_WARN_AND_RETURN_UNLESS(res.IsValid(), ElementId::InvalidID, L"invalid object id",L"GDMPLab",L"2024-03-30");

    ut->Commit();

    return res;
}

OwnerPtr<IGraphicsNodeGroup> CmdCreateLinearInstance::OnLineUpdate(gcmp::IUiView* pCurrentView, const gcmp::Vector3d& startPt, const gcmp::Vector3d& endPt)
{
    if ((startPt - endPt).IsZero(Constants::MIN_MODEL_SIZE))
        return nullptr;

    if (!m_isPreview)
        return nullptr;

    IDocument* pDoc = UiDocumentViewUtils::GetCurrentDocument();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc, L"doc为空",L"GDMPLab",L"2024-03-30");
    IModelView* view = pCurrentView->GetModelView();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(view, L"view为空",L"GDMPLab",L"2024-03-30");

    std::vector<Vector3d> pts;
    pts.emplace_back(Vector3d(startPt.X(), startPt.Y(), startPt.Z()));
    pts.emplace_back(Vector3d(endPt.X(), endPt.Y(), endPt.Z()));

    gcmp::OwnerPtr<IUserTransaction> ut = IUserTransaction::Create(pDoc, (GBMP_TR(L"创建GBMP普通两点线式族实例")));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(ut, L"ut为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IPointArrayInstanceInput> opPointArrayInstanceInput = IPointArrayInstanceInput::Create(UiDocumentViewUtils::GetCurrentDocument(), UIWorkLevelUtilTemp::GetWorkLevelId(view), m_familyId, m_familyTypeName, pts);
    opPointArrayInstanceInput->SetCanBeShared(false);
    IInstance* assistInstance = IInstance::CreateByPointArray(opPointArrayInstanceInput.get(), false);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(assistInstance, L"instance为空",L"GDMPLab",L"2024-03-30");

    assistInstance->SetExpandSubInstances(false);
    IRegenerator* pRegenerator = pDoc->GetRegenerator();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pRegenerator, L"pRegenerator为空",L"GDMPLab",L"2024-03-30");
    pRegenerator->RegenerateElement(assistInstance->GetElementId());

    OwnerPtr<IGraphicsElementShape> tempGrep = TransferOwnershipCast<IGraphicsElementShape>(assistInstance->GetElementModelShape()->GetGraphicsElementShape()->Clone());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(tempGrep != nullptr, L"无效的pTemp指针",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IGraphicsNodeGroup> tempGpGrep = gcmp::GbmpGraphicsNodeUtils::TransferGRepToGGroup(TransferOwnership(tempGrep));
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(tempGpGrep, L"将图形表达转换成图形节点组失败",L"GDMPLab",L"2024-03-30");
    tempGpGrep->SetIsSnappable(false);

    ut->Rollback();

    if (pDoc)
    {
        GraphicsNodeUtils::CleanGraphicsNodeStyleAndMaterial(pDoc, tempGpGrep.get());
        const IGraphicsMaterialManager* pMaterialMgr = pDoc->GetGraphicsMaterialManager();
        DBG_WARN_AND_RETURN_UNLESS(pMaterialMgr, tempGpGrep, L"pStyleMgr为空。",L"GDMPLab",L"2024-03-30");
        tempGpGrep->SetGraphicsStyleId(pMaterialMgr->GetGraphicsMaterialIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_TEMP_STYLE));
    }
    else
    {
        DBG_WARN(L"pDoc == nullptr",L"GDMPLab",L"2024-03-30");
    }
    return TransferOwnership(tempGpGrep);
}

const std::wstring CmdCreateLinearInstance::DefinePromptMessage(DrawLineStatus drawLineStatus)
{
    switch (drawLineStatus)
    {
    case DrawLineStatus::Getting_StartPoint:
        return GBMP_TR(L"族的实例化：请输入族实例的起始放置点");
    case DrawLineStatus::Getting_EndPoint:
        return GBMP_TR(L"族的实例化：请输入族实例的终止放置点");
    default:
        return L"";
    }
}

void RegisterCmdCreateLinearInstanceCommand()
{
    ICommandManager::Get()->RegisterCommand(TR_MODULE_NAME, NEW_AS_OWNER_PTR(CmdCreateLinearInstance));
}
ONE_TIME_INITIALIZER(RegisterCmdCreateLinearInstanceCommand)
